// -*- C++ -*-

#ifndef _PARAMETER_H_
#define _PARAMETER_H_

#include <string>
using std::string;
#include <vector>
using std::vector;
#include <utility>
using std::pair;
#include <set>
using std::set;
#include <iostream>
using std::ostream;

#include <cstring>
//------------------------------------------------------------------------------

class Parameter {
public:
  Parameter(const char*,int=-1);
  Parameter(const Parameter&);
  virtual ~Parameter();
  virtual Parameter* duplicate() const = 0;
  virtual void assignInteger(int);
  virtual void assignDouble(double);
  virtual void assignString(const char*);
  virtual void assignToken(int);
  virtual void assignIntegerList(const char*);
  virtual void assignDoubleList(const char*);
  virtual void assignStringList(const char*);
  virtual void assignTokenList(const char*);
  virtual void assignIntegerRange(const char*);
  virtual int getOneInteger() const;
  virtual double getOneDouble() const;
  virtual const char* getOneString() const;
  virtual const char* getOneToken() const;
  virtual vector<int> getOneIntegerList() const;
  virtual vector<double> getOneDoubleList() const;
  virtual vector<string> getOneStringList() const;
  virtual vector<string> getOneTokenList() const;
  virtual vector<pair<int,int> > getOneIntegerRange() const;
  virtual Parameter* getObject(int);
  virtual const Parameter* getObject(int) const;
  virtual Parameter* getMultiObject(const char*);
  virtual void dump(FILE*, const char*) const = 0;
  virtual void dumpAssigned(ostream&, const char*) const = 0;
  const char* getName() const { return name.c_str(); }
  const char* getTag() const { return tag.c_str(); }
  void setTag(const char* n) { tag = n; }
  virtual bool isAssigned() const { return isAsgn; }
  bool isActive() const;
  void addComment(const string&);
  void dumpWithComments(FILE*,const char*) const;
  virtual bool merge(Parameter* a);
  
protected:
  bool   isAsgn;
  int    moduleTag;
  string name;
  string tag;
  vector<string> comments;
};

//------------------------------------------------------------------------------

class IntegerParameter;
class DoubleParameter;
class StringParameter;
class TokenParameter;

class ClassParameter : public Parameter {
public:
  ClassParameter(const char*,int=-1);
  ClassParameter(const ClassParameter&);
  virtual ~ClassParameter();
  Parameter* duplicate() const;
  Parameter* addObject(Parameter*);
  Parameter* getObject(int);
  const Parameter* getObject(int) const;
  Parameter* getMultiObject(const char*);
  ClassParameter& add(const char*,int m=-1);
  bool merge(Parameter*);
  ClassParameter& addMultiple(const char*,int m=-1);
  void addInteger(const char*, int,int m=-1);
  void addDouble(const char*, double,int m=-1);
  void addString(const char*, const char*,int m=-1);
  void addToken(const char*, int, ...);
  void addToken(int, const char*, int, ...);
  void addToken(const char*,const set<string>&,const string&,int m=-1);
  void addIntegerList(const char*,int m=-1);
  void addDoubleList(const char*,int m=-1);
  void addStringList(const char*,int m=-1);
  void addTokenList(const char*,int, ...);
  void addTokenList(int, const char*,int , ...);
  void addTokenList(const char*,const set<string>&,const string&,int m=-1);
  void addIntegerRange(const char*,int m=-1);
  ClassParameter& get(const char*, int = -1);
  ClassParameter& get(const char*,const char*);
  ClassParameter& get(const char*,const string&);
  ClassParameter* find(const char*, int = -1);
  ClassParameter* find(const char*,const char*);

  IntegerParameter& getIntegerParameter(const char*) const;
  DoubleParameter&  getDoubleParameter (const char*) const;
  StringParameter&  getStringParameter (const char*) const;
  TokenParameter&   getTokenParameter  (const char*) const;
  template<class ParameterClass>
  ParameterClass& getParameterTemplate(const char*) const;
  template<class ParameterClass>
  ParameterClass* findParameterTemplate(const char*) const;
  
  virtual int getInteger(const char*) const;
  virtual double getDouble(const char*) const;
  virtual const char* getString(const char*) const;
  virtual const char* getToken(const char*) const;
  virtual vector<int> getIntegerList(const char*) const;
  virtual vector<double> getDoubleList(const char*) const;
  virtual vector<double> getDoubleVector(const char*) const;
  virtual vector<string> getStringList(const char*) const;
  virtual vector<string> getTokenList(const char*) const;
  virtual vector<pair<int,int> > getIntegerRange(const char*) const;
  virtual bool isAssigned() const;
  virtual bool isAssigned(const char*) const;
  virtual int size() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
protected:
  vector<Parameter*> subAsgn;
  vector<int> subToken;
};

//------------------------------------------------------------------------------

class MultiClassParameter : public ClassParameter {
public:
  MultiClassParameter(const char*,int=-1);
  MultiClassParameter(const MultiClassParameter&);
  ~MultiClassParameter();
  bool merge(Parameter*);
  Parameter* duplicate() const;
  Parameter* getMultiObject(const char*);
  ClassParameter* get(int);
  int getInteger(const char*) const;
  double getDouble(const char*) const;
  const char* getString(const char*) const;
  const char* getToken(const char*) const;
  vector<int> getIntegerList(const char*) const;
  vector<double> getDoubleList(const char*) const;
  vector<double> getDoubleVector(const char*) const;
  vector<string> getStringList(const char*) const;
  vector<string> getTokenList(const char*) const;
  vector<pair<int,int> > getIntegerRange(const char*) const;
  bool isAssigned(const char*) const;
  bool isAssigned() const;
  int size() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
private:
  vector<ClassParameter*> list;
};

//------------------------------------------------------------------------------

class IntegerParameter : public Parameter {
public:
  IntegerParameter(const char*, int,int=-1);
  IntegerParameter(const IntegerParameter&);
  ~IntegerParameter();
  Parameter* duplicate() const;
  void assignInteger(int);
  int getOneInteger() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
  IntegerParameter& operator= (int);
  bool merge(Parameter* a);
private:
  int val;
};

//------------------------------------------------------------------------------

class DoubleParameter : public Parameter {
public:
  DoubleParameter(const char*, double,int=-1);
  DoubleParameter(const DoubleParameter&);
  ~DoubleParameter();
  Parameter* duplicate() const;
  void assignInteger(int);
  void assignDouble(double);
  double getOneDouble() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
  DoubleParameter& operator= (double);
  bool merge(Parameter* a);
private:
  double val;
};
  
//------------------------------------------------------------------------------

class StringParameter : public Parameter {
public:
  StringParameter(const char*, const char*,int=-1);
  StringParameter(const StringParameter&);
  ~StringParameter();
  Parameter* duplicate() const;
  void assignString(const char*);
  const char* getOneString() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
  StringParameter& operator= (const string&);
  bool merge(Parameter* a);
private:
  string val;
};

//------------------------------------------------------------------------------

class TokenParameter : public Parameter {
public:
  TokenParameter(const char*, const vector<string>&,int=-1);
  TokenParameter(const TokenParameter&);
  ~TokenParameter();
  Parameter* duplicate() const;
  void assignToken(int);
  const char* getOneToken() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
  TokenParameter& operator=(const string&);
  bool merge(Parameter*);
private:
  int val;
  vector<int> tk;
};

//------------------------------------------------------------------------------

template<class T>
class ListParameter : public Parameter {
public:
  ListParameter(const char*,int=-1);
  ListParameter(const ListParameter&);
  virtual ~ListParameter();
  Parameter* duplicate() const;
  void assignIntegerList(const char*);
  void assignDoubleList(const char*);
  void assignStringList(const char*);
  void assignIntegerRange(const char*);
  vector<int> getOneIntegerList() const;
  vector<double> getOneDoubleList() const;
  vector<string> getOneStringList() const;
  vector<pair<int,int> > getOneIntegerRange() const;
  virtual void dump(FILE*, const char*) const;
  virtual void dumpAssigned(ostream&, const char*) const;
  bool merge(Parameter* a);
protected:
  vector<T> val;
  virtual void addToList(const char*);
  virtual string convertToString(const T&) const;
  void assignList(const char*);
  void linedump(FILE*, const char*) const;
  void linedump(ostream&, const char*) const;
private:
  vector<T> getList() const;
};

//------------------------------------------------------------------------------

class TokenListParameter : public ListParameter<int> {
public:
  TokenListParameter(const char*, const vector<string>&,int=-1);
  TokenListParameter(const TokenListParameter&);
  ~TokenListParameter();
  Parameter* duplicate() const;
  void assignTokenList(const char*);
  vector<string> getOneTokenList() const;
  void dump(FILE*, const char*) const;
  void dumpAssigned(ostream&, const char*) const;
  bool merge(Parameter*);
private:
  vector<int> tk;
  void addToList(const char*);
  string convertToString(const int&) const;
};

//------------------------------------------------------------------------------

#include "Parameter.ipp"

#endif
